#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

using namespace MySem;
using namespace MyMutex;

const int defualt_cap = 1;
template <typename T>
class CirQueue
{
public:
    CirQueue(int cap = defualt_cap)
        : _cq(cap),
          _cap(cap),
          _producer_sem(cap), // 空位的数量
          _p_index(0),
          _consumer_sem(0), // 数据的数量
          _c_index(0)
    {
    }

    void Equeue(const T &data) // 生产者
    {
        _producer_sem.P(); // 申请信号量
        {
            LockGuard lg(&_producer_mutex);
            _cq[_p_index++] = data; // 生产,生产完了要往后走
            _p_index %= _cap;       // 维持环状结构
        }
        _consumer_sem.V(); // 让消费者的信号量+1
    }

    T Pop() // 消费者
    {
        T data;
        _consumer_sem.P(); // 申请信号量
        {
            LockGuard lg(&_consumer_mutex);
            data = _cq[_c_index++]; // 获取数据，获取之后往后走
            _c_index %= _cap;       // 维持环状结构
        }
        _producer_sem.V(); // 让生产者信号量+1
        return data;
    }

    ~CirQueue()
    {
    }

private:
    std::vector<T> _cq;
    int _cap;

    Sem _producer_sem; // 生产者信号量
    Sem _consumer_sem; // 消费者信号量

    int _p_index; // 生产者下标
    int _c_index; // 消费者下标

    Mutex _producer_mutex; // 生产者的互斥锁
    Mutex _consumer_mutex; // 消费者的互斥锁
};